import {Box,Box_Type} from "./box"
import D from "../Data"

export default class manager {
    private mapW: number;
    private mapH: number;
    private static intance: manager;
    public boxs: Array<Array<Box>>=new Array<Array<Box>>();
    public openList: Array<Box> = new Array<Box>();
    public closeList: Array<Box> = new Array<Box>();

    public static get Intance(): manager {        
        if (manager.intance == null) {
            manager.intance = new manager();
        }
        return manager.intance;
    }

    public initMapInfo(w: number, h: number) {
        this.mapH = h;
        this.mapW = w;
        for (let i = 0; i < w; i++) {
            this.boxs[i]=new Array<Box>();
            for (let j = 0; j < h; j++) {
                let box: Box = new Box(i, j, Box_Type.walk);
                this.boxs[i][j] = box;
            }
        }
    }

    public FindPath(start: Laya.Vector2, end: Laya.Vector2): Array<Box> {
        if (start.x < 0 || start.x >= this.mapW || start.y < 0 || start.y >= this.mapH || end.x < 0 || end.x >= this.mapW || end.y < 0 || end.y >= this.mapH)
        {
            return null;
        }
        let startP:Box=this.boxs[start.x][start.y];
        let endP:Box=this.boxs[end.x][end.y];
        if(startP.type==Box_Type.stop|| endP.type == Box_Type.stop)
        {
            return null;
        }
        this.openList.splice(0,this.openList.length);
        this.closeList.splice(0,this.closeList.length);
        startP.father = null;
        startP.f = 0;
        startP.g = 0;
        startP.h = 0;
        this.closeList.push(startP);
        while(true)
        {
            this.FindNearlyBoxToOpenList(startP.x, startP.y - 1, 1, startP, endP);
            this.FindNearlyBoxToOpenList(startP.x, startP.y + 1, 1, startP, endP);
            this.FindNearlyBoxToOpenList(startP.x - 1, startP.y, 1, startP, endP);
            this.FindNearlyBoxToOpenList(startP.x + 1, startP.y, 1, startP, endP);       
            if(this.openList.length==0)
            {
                return null;
            }
            this.openList.sort(this.SortOpenList);
            this.closeList.push(this.openList[0]);
            startP = this.openList[0];
            this.openList.splice(0,1);
            if (startP == endP)
            {
                let path:Array<Box>=new Array<Box>();
                path.push(endP);
                while(endP.father!=null)
                {
                    path.push(endP.father);
                    endP = endP.father;
                }
                path.reverse();
                return path;
            }
        }
        return null;
    }

    private SortOpenList(a:Box,b:Box):number
    {
        if(a.f>b.f)
        {
            return 1;
        }
        else
        {
            return -1;
        }
    }

    private FindNearlyBoxToOpenList(x:number, y:number, g:number, father:Box, end:Box)
    {
        if (x < 0 || x >= this.mapW || y < 0 || y >= this.mapH)
        {
            return;
        }
        let box:Box=this.boxs[x][y];

        if (box == null || box.type == Box_Type.stop || this.IsSame(this.closeList,box)|| this.IsSame(this.openList,box))
        {
            return;
        }
        box.father = father;
        box.g = father.g + g;
        box.h = Math.abs(end.x - box.x) + Math.abs(end.y - box.y);
        box.f = box.g + box.h;
        this.openList.push(box);
    }

    private IsSame(arr:Array<Box>,box:Box):boolean{
        let b:boolean=false;
        arr.forEach(element => {
            if(element.x==box.x&&element.y==box.y){
                b=true;
                return b;
            }
        });
        return b;
    }
}